﻿using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using Tssipl.PaymentAdapter.Core;

namespace Tssipl.PaymentAdapter.MessageFormat.Sfms
{
    public class SfmsMessageParser
    {
        /** Attempts to parse a Sfms message from the provided
         * content and return it.  The message must be properly formed.
         * 
         * @param Contents a string containing a Sfms message.
         * @return a parsed message if successful contained in a MessageParseResults object.
         * @throws IOException if an error occurs while parsing.
         */
        static public MessageParseResults parseMessage(String Contents) //HACK throws IOException
        {
            List<String> errorList = new List<String>();

            String contents = Contents;
            int block1Elements = findAndCountMatches(contents, "{A:");
            if (block1Elements < 1)
                errorList.Add("Missing block A in message.");
            else if (block1Elements > 1)
            {
                errorList.Add("Too many block A entries in message.  Does this have an ACK/UAK header?");

                // determine if we have an ACK/UAK then remove it
                int index = contents.IndexOf("{A:F01");
                if (block1Elements == 2 &&
                    (contents.StartsWith("{A:F21") || contents.StartsWith("{A:F31")) &&
                    index >= 0)
                {
                    contents = contents.Substring(index);
                    block1Elements = findAndCountMatches(contents, "{A:");		// recount block 1s

                    if (block1Elements > 1)
                        errorList.Add("Sfms message contains more than one block 1 even after removing header.. Unable to parse.");
                }
                else
                    errorList.Add("Sfms message contains more than one block 1. Unable to parse.");
            }

            if (block1Elements == 1)
            {
                //int block2Elements = findAndCountMatches(contents,"{2:");
                //int block3Elements = findAndCountMatches(contents,"{3:");
                int block4Elements = findAndCountMatches(contents, "{4:");
                //int block5Elements = findAndCountMatches(contents,"{5:");

                Boolean canParse = true;
                //if (block2Elements < 1)
                //    errorList.Add("Sfms message is missing a block 2.");
                //else if (block2Elements > 2)
                //    {
                //    canParse = true;
                //    errorList.Add("Sfms message contains more than one block 2.");
                //    }

                if (block4Elements < 1)
                    errorList.Add("Sfms message is missing a block 4.");
                else if (block4Elements > 1)
                {
                    errorList.Add("Sfms message contains more than one block 4.");
                    canParse = true;
                }
                //if (block3Elements > 1)
                //    {
                //    errorList.Add("Sfms message contains more than one block 3.");
                //    canParse = true;
                //    }

                //if (block5Elements > 1)
                //    {
                //    errorList.Add("Sfms message contains more than one block 5.");
                //    canParse = true;
                //    }

                if (contents.IndexOf("-}") < 0)
                {
                    errorList.Add("Sfms message is missing a dash-curly on message.");
                    canParse = true;
                }
                else if (canParse)
                {
                    // make sure that block 4 is correctly started and ended without 
                    // intervening open curly brace
                    int block4 = contents.IndexOf("{4:");
                    int dashCurly = contents.IndexOf("-}", block4 + 1);
                    int nextBrace = contents.IndexOf("{", block4 + 1);
                    if (dashCurly < 0 || (nextBrace >= 0 && dashCurly > nextBrace))
                    {
                        errorList.Add("Sfms message is missing a dash-curly on block 4.");
                        canParse = true;
                    }
                }

                // check order of blocks is correct (1, 2, 3, 4, 5)
                if (canParse)
                {
                    int block1Offset = contents.IndexOf("{A:");
                    //int block2Offset = contents.IndexOf("{2:");
                    int block4Offset = contents.IndexOf("{4:");

                    if (block1Offset > block4Offset)
                    {
                        errorList.Add("Sfms message's block 1 does not occur before block 4.");
                        canParse = true;
                    }
                    //if (block2Offset > block4Offset)
                    //    {
                    //    errorList.Add("Sfms message's block 2 does not occur before block 4.");
                    //    canParse = true;
                    //    }
                    //if (block1Offset > block4Offset)
                    //    {
                    //    errorList.Add("Sfms message's block 1 does not occur before block 4.");
                    //    canParse = true;
                    //    }

                    //if (block3Elements == 1)
                    //    {
                    //    int block3Offset = contents.IndexOf("{3:");
                    //    if (block1Offset > block3Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 1 does not occur before block 3.");
                    //        canParse = true;
                    //        }
                    //    if (block2Offset > block3Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 2 does not occur before block 3.");
                    //        canParse = true;
                    //        }
                    //    if (block3Offset > block4Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 3 does not occur before block 4.");
                    //        canParse = true;
                    //        }
                    //    }
                    //if (block5Elements == 1)
                    //    {
                    //    int block5Offset = contents.IndexOf("{5:");
                    //    if (block1Offset > block5Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 1 does not occur before block 5.");
                    //        canParse = true;
                    //        }
                    //    if (block2Offset > block5Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 2 does not occur before block 5.");
                    //        canParse = true;
                    //        }
                    //    if (block4Offset > block5Offset)
                    //        {
                    //        errorList.Add("Sfms message's block 4 does not occur before block 5.");
                    //        canParse = true;
                    //        }
                    //    }
                }

                // now to parse the contents of the Sfms message's blocks
                if (canParse)
                {
                    // strip the parts
                    int offset1 = contents.IndexOf("{A:");
                    //int offset2 = contents.IndexOf("{2:");
                    //int offset3 = contents.IndexOf("{3:");
                    int offset4 = contents.IndexOf("{4:");
                    int offset5 = contents.IndexOf("{5:");

                    String block1Contents = contents.SubstringJava(offset1, offset4).Trim();
                    //String block2Contents = null;
                    //String block3Contents = null;
                    //if (offset3 >= 0)
                    //    {
                    //    block2Contents = contents.SubstringJava(offset2,offset3).Trim();
                    //    block3Contents = contents.SubstringJava(offset3,offset4).Trim();
                    //    }
                    //else
                    //    block2Contents = contents.SubstringJava(offset2,offset4).Trim();
                    String block4Contents = null;
                    String block5Contents = null;
                    if (offset5 >= 0)
                    {
                        block4Contents = contents.SubstringJava(offset4, offset5).Trim();
                        block5Contents = contents.Substring(offset5).Trim();
                    }
                    else
                        block4Contents = contents.Substring(offset4).Trim();

                    try
                    {
                        SfmsBlock1 block1 = new SfmsBlock1(block1Contents.SubstringJava(3, block1Contents.Length - 1));

                        // ISfmsBlock block2 = null;
                        //if (block2Contents[3]== 'I')//.charAt(3) == 'I')
                        //    block2 =( new SfmsBlock2Inbound(block2Contents.SubstringJava(3,block2Contents.Length - 1)));
                        //else if (block2Contents[3] == 'O')//.charAt(3) == 'O')
                        //    block2 =( new SfmsBlock2Outbound(block2Contents.SubstringJava(3,block2Contents.Length - 1)));
                        //else
                        //    throw new Exception("Sfms message has an invalid block 2: Neither I nor O.");

                        // SfmsBlock3 block3 = null;
                        //if (block3Contents != null)
                        //    block3 = new SfmsBlock3(block3Contents.SubstringJava(3,block3Contents.Length - 1));

                        SfmsBlock4 block4 = new SfmsBlock4(block4Contents.SubstringJava(5, block4Contents.Length - 2));

                        //SfmsBlock5 block5 = null;
                        //if (block5Contents != null)
                        //    block5 = new SfmsBlock5(block5Contents.SubstringJava(3,block5Contents.Length - 1));

                        SfmsMessage msg = new SfmsMessage(block1, block4);

                        List<Field> fields = new List<Field>();
                        //for (SfmsField field : block4.getFields())
                        foreach (Field field in block4.getFields())
                            fields.Add(field);
                        return new MessageParseResults(msg, fields, errorList);
                    }
                    catch (Exception ee)
                    {
                        errorList.Add("Sfms message parser failed with an exception: " + ee.Message + ".");
                    }
                }
            }

            //FedWireMessage message = new FedWireMessage(fieldList,support.errorList);
            return new MessageParseResults(null, new List<Field>(), errorList);
        }


        /** Counts the number of occurrences of the needle pattern in the
         * haystack.
         * 
         * @param Haystack the string to search.
         * @param Needle the pattern to find.
         * @return the total number of occurrences of the needle in the haystack.
         */
        static private int findAndCountMatches(String Haystack, String Needle)
        {
            int total = 0;
            for (int offset = -1; offset < Haystack.Length; )
            {
                offset = Haystack.IndexOf(Needle, offset + 1);
                if (offset < 0)
                    break;
                ++total;
            }

            return total;
        }
    }
}